home *** CD-ROM | disk | FTP | other *** search
/ PC World 2008 February (DVD) / PCWorld_2008-02_DVD.iso / v cisle / PHP / PHP.exe / xampp-win32-1.6.5-installer.exe / php / PEAR / Pager / Common.php next >
Encoding:
PHP Script  |  2007-12-20  |  42.1 KB  |  1,507 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3.  
  4. /**
  5.  * Contains the Pager_Common class
  6.  *
  7.  * PHP versions 4 and 5
  8.  *
  9.  * LICENSE: Redistribution and use in source and binary forms, with or without
  10.  * modification, are permitted provided that the following conditions are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. The name of the author may not be used to endorse or promote products
  17.  *    derived from this software without specific prior written permission.
  18.  *
  19.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
  20.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  21.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  22.  * IN NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY
  23.  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  24.  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  25.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  26.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  28.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29.  *
  30.  * @category   HTML
  31.  * @package    Pager
  32.  * @author     Lorenzo Alberton <l dot alberton at quipo dot it>
  33.  * @author     Richard Heyes <richard@phpguru.org>
  34.  * @copyright  2003-2006 Lorenzo Alberton, Richard Heyes
  35.  * @license    http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
  36.  * @version    CVS: $Id: Common.php,v 1.57 2006/10/11 16:01:33 quipo Exp $
  37.  * @link       http://pear.php.net/package/Pager
  38.  */
  39.  
  40. /**
  41.  * Two constants used to guess the path- and file-name of the page
  42.  * when the user doesn't set any other value
  43.  */
  44. if (substr($_SERVER['PHP_SELF'], -1) == '/') {
  45.     $http = !empty($_SERVER['HTTPS']) ? 'https://' : 'http://';
  46.     define('CURRENT_FILENAME', '');
  47.     define('CURRENT_PATHNAME', $http.$_SERVER['HTTP_HOST'].str_replace('\\', '/', $_SERVER['PHP_SELF']));
  48. } else {
  49.     define('CURRENT_FILENAME', preg_replace('/(.*)\?.*/', '\\1', basename($_SERVER['PHP_SELF'])));
  50.     define('CURRENT_PATHNAME', str_replace('\\', '/', dirname($_SERVER['PHP_SELF'])));
  51. }
  52. /**
  53.  * Error codes
  54.  */
  55. define('PAGER_OK',                         0);
  56. define('ERROR_PAGER',                     -1);
  57. define('ERROR_PAGER_INVALID',             -2);
  58. define('ERROR_PAGER_INVALID_PLACEHOLDER', -3);
  59. define('ERROR_PAGER_INVALID_USAGE',       -4);
  60. define('ERROR_PAGER_NOT_IMPLEMENTED',     -5);
  61.  
  62. /**
  63.  * Pager_Common - Common base class for [Sliding|Jumping] Window Pager
  64.  * Extend this class to write a custom paging class
  65.  *
  66.  * @category   HTML
  67.  * @package    Pager
  68.  * @author     Lorenzo Alberton <l dot alberton at quipo dot it>
  69.  * @author     Richard Heyes <richard@phpguru.org>
  70.  * @copyright  2003-2005 Lorenzo Alberton, Richard Heyes
  71.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  72.  * @link       http://pear.php.net/package/Pager
  73.  */
  74. class Pager_Common
  75. {
  76.     // {{{ class vars
  77.  
  78.     /**
  79.      * @var integer number of items
  80.      * @access private
  81.      */
  82.     var $_totalItems;
  83.  
  84.     /**
  85.      * @var integer number of items per page
  86.      * @access private
  87.      */
  88.     var $_perPage     = 10;
  89.  
  90.     /**
  91.      * @var integer number of page links for each window
  92.      * @access private
  93.      */
  94.     var $_delta       = 10;
  95.  
  96.     /**
  97.      * @var integer current page number
  98.      * @access private
  99.      */
  100.     var $_currentPage = 1;
  101.  
  102.     /**
  103.      * @var integer total pages number
  104.      * @access private
  105.      */
  106.     var $_totalPages  = 1;
  107.  
  108.     /**
  109.      * @var string CSS class for links
  110.      * @access private
  111.      */
  112.     var $_linkClass   = '';
  113.  
  114.     /**
  115.      * @var string wrapper for CSS class name
  116.      * @access private
  117.      */
  118.     var $_classString = '';
  119.  
  120.     /**
  121.      * @var string path name
  122.      * @access private
  123.      */
  124.     var $_path        = CURRENT_PATHNAME;
  125.  
  126.     /**
  127.      * @var string file name
  128.      * @access private
  129.      */
  130.     var $_fileName    = CURRENT_FILENAME;
  131.     
  132.     /**
  133.      * @var boolean If false, don't override the fileName option. Use at your own risk.
  134.      * @access private
  135.      */
  136.     var $_fixFileName = true;
  137.  
  138.     /**
  139.      * @var boolean you have to use FALSE with mod_rewrite
  140.      * @access private
  141.      */
  142.     var $_append      = true;
  143.  
  144.     /**
  145.      * @var string specifies which HTTP method to use
  146.      * @access private
  147.      */
  148.     var $_httpMethod  = 'GET';
  149.     
  150.     /**
  151.      * @var string specifies which HTML form to use
  152.      * @access private
  153.      */
  154.     var $_formID  = '';
  155.  
  156.     /**
  157.      * @var boolean whether or not to import submitted data
  158.      * @access private
  159.      */
  160.     var $_importQuery = true;
  161.  
  162.     /**
  163.      * @var string name of the querystring var for pageID
  164.      * @access private
  165.      */
  166.     var $_urlVar      = 'pageID';
  167.  
  168.     /**
  169.      * @var array data to pass through the link
  170.      * @access private
  171.      */
  172.     var $_linkData    = array();
  173.  
  174.     /**
  175.      * @var array additional URL vars
  176.      * @access private
  177.      */
  178.     var $_extraVars   = array();
  179.     
  180.     /**
  181.      * @var array URL vars to ignore
  182.      * @access private
  183.      */
  184.     var $_excludeVars = array();
  185.  
  186.     /**
  187.      * @var boolean TRUE => expanded mode (for Pager_Sliding)
  188.      * @access private
  189.      */
  190.     var $_expanded    = true;
  191.     
  192.     /**
  193.      * @var boolean TRUE => show accesskey attribute on <a> tags
  194.      * @access private
  195.      */
  196.     var $_accesskey   = false;
  197.  
  198.     /**
  199.      * @var string extra attributes for the <a> tag
  200.      * @access private
  201.      */
  202.     var $_attributes  = '';
  203.  
  204.     /**
  205.      * @var string alt text for "first page" (use "%d" placeholder for page number)
  206.      * @access private
  207.      */
  208.     var $_altFirst     = 'first page';
  209.  
  210.     /**
  211.      * @var string alt text for "previous page"
  212.      * @access private
  213.      */
  214.     var $_altPrev     = 'previous page';
  215.  
  216.     /**
  217.      * @var string alt text for "next page"
  218.      * @access private
  219.      */
  220.     var $_altNext     = 'next page';
  221.  
  222.     /**
  223.      * @var string alt text for "last page" (use "%d" placeholder for page number)
  224.      * @access private
  225.      */
  226.     var $_altLast     = 'last page';
  227.  
  228.     /**
  229.      * @var string alt text for "page"
  230.      * @access private
  231.      */
  232.     var $_altPage     = 'page';
  233.  
  234.     /**
  235.      * @var string image/text to use as "prev" link
  236.      * @access private
  237.      */
  238.     var $_prevImg     = '<< Back';
  239.  
  240.     /**
  241.      * @var string image/text to use as "next" link
  242.      * @access private
  243.      */
  244.     var $_nextImg     = 'Next >>';
  245.  
  246.     /**
  247.      * @var string link separator
  248.      * @access private
  249.      */
  250.     var $_separator   = '';
  251.  
  252.     /**
  253.      * @var integer number of spaces before separator
  254.      * @access private
  255.      */
  256.     var $_spacesBeforeSeparator = 0;
  257.  
  258.     /**
  259.      * @var integer number of spaces after separator
  260.      * @access private
  261.      */
  262.     var $_spacesAfterSeparator  = 1;
  263.  
  264.     /**
  265.      * @var string CSS class name for current page link
  266.      * @access private
  267.      */
  268.     var $_curPageLinkClassName  = '';
  269.  
  270.     /**
  271.      * @var string Text before current page link
  272.      * @access private
  273.      */
  274.     var $_curPageSpanPre        = '';
  275.  
  276.     /**
  277.      * @var string Text after current page link
  278.      * @access private
  279.      */
  280.     var $_curPageSpanPost       = '';
  281.  
  282.     /**
  283.      * @var string Text before first page link
  284.      * @access private
  285.      */
  286.     var $_firstPagePre  = '[';
  287.  
  288.     /**
  289.      * @var string Text to be used for first page link
  290.      * @access private
  291.      */
  292.     var $_firstPageText = '';
  293.  
  294.     /**
  295.      * @var string Text after first page link
  296.      * @access private
  297.      */
  298.     var $_firstPagePost = ']';
  299.  
  300.     /**
  301.      * @var string Text before last page link
  302.      * @access private
  303.      */
  304.     var $_lastPagePre   = '[';
  305.  
  306.     /**
  307.      * @var string Text to be used for last page link
  308.      * @access private
  309.      */
  310.     var $_lastPageText  = '';
  311.  
  312.     /**
  313.      * @var string Text after last page link
  314.      * @access private
  315.      */
  316.     var $_lastPagePost  = ']';
  317.  
  318.     /**
  319.      * @var string Will contain the HTML code for the spaces
  320.      * @access private
  321.      */
  322.     var $_spacesBefore  = '';
  323.  
  324.     /**
  325.      * @var string Will contain the HTML code for the spaces
  326.      * @access private
  327.      */
  328.     var $_spacesAfter   = '';
  329.  
  330.     /**
  331.      * @var string $_firstLinkTitle
  332.      * @access private
  333.      */
  334.     var $_firstLinkTitle = 'first page';
  335.  
  336.     /**
  337.      * @var string $_nextLinkTitle
  338.      * @access private
  339.      */
  340.     var $_nextLinkTitle = 'next page';
  341.  
  342.     /**
  343.      * @var string $_prevLinkTitle
  344.      * @access private
  345.      */
  346.     var $_prevLinkTitle = 'previous page';
  347.  
  348.     /**
  349.      * @var string $_lastLinkTitle
  350.      * @access private
  351.      */
  352.     var $_lastLinkTitle = 'last page';
  353.  
  354.     /**
  355.      * @var string Text to be used for the 'show all' option in the select box
  356.      * @access private
  357.      */
  358.     var $_showAllText   = '';
  359.  
  360.     /**
  361.      * @var array data to be paged
  362.      * @access private
  363.      */
  364.     var $_itemData      = null;
  365.  
  366.     /**
  367.      * @var boolean If TRUE and there's only one page, links aren't shown
  368.      * @access private
  369.      */
  370.     var $_clearIfVoid   = true;
  371.  
  372.     /**
  373.      * @var boolean Use session for storing the number of items per page
  374.      * @access private
  375.      */
  376.     var $_useSessions   = false;
  377.  
  378.     /**
  379.      * @var boolean Close the session when finished reading/writing data
  380.      * @access private
  381.      */
  382.     var $_closeSession  = false;
  383.  
  384.     /**
  385.      * @var string name of the session var for number of items per page
  386.      * @access private
  387.      */
  388.     var $_sessionVar    = 'setPerPage';
  389.  
  390.     /**
  391.      * Pear error mode (when raiseError is called)
  392.      * (see PEAR doc)
  393.      *
  394.      * @var int $_pearErrorMode
  395.      * @access private
  396.      */
  397.     var $_pearErrorMode = null;
  398.  
  399.     // }}}
  400.     // {{{ public vars
  401.  
  402.     /**
  403.      * @var string Complete set of links
  404.      * @access public
  405.      */
  406.     var $links = '';
  407.  
  408.     /**
  409.      * @var string Complete set of link tags
  410.      * @access public
  411.      */
  412.     var $linkTags = '';
  413.  
  414.     /**
  415.      * @var array Array with a key => value pair representing
  416.      *            page# => bool value (true if key==currentPageNumber).
  417.      *            can be used for extreme customization.
  418.      * @access public
  419.      */
  420.     var $range = array();
  421.     
  422.     /**
  423.      * @var array list of available options (safety check)
  424.      * @access private
  425.      */
  426.     var $_allowed_options = array(
  427.         'totalItems',
  428.         'perPage',
  429.         'delta',
  430.         'linkClass',
  431.         'path',
  432.         'fileName',
  433.         'fixFileName',
  434.         'append',
  435.         'httpMethod',
  436.         'formID',
  437.         'importQuery',
  438.         'urlVar',
  439.         'altFirst',
  440.         'altPrev',
  441.         'altNext',
  442.         'altLast',
  443.         'altPage',
  444.         'prevImg',
  445.         'nextImg',
  446.         'expanded',
  447.         'accesskey',
  448.         'attributes',
  449.         'separator',
  450.         'spacesBeforeSeparator',
  451.         'spacesAfterSeparator',
  452.         'curPageLinkClassName',
  453.         'curPageSpanPre',
  454.         'curPageSpanPost',
  455.         'firstPagePre',
  456.         'firstPageText',
  457.         'firstPagePost',
  458.         'lastPagePre',
  459.         'lastPageText',
  460.         'lastPagePost',
  461.         'firstLinkTitle',
  462.         'nextLinkTitle',
  463.         'prevLinkTitle',
  464.         'lastLinkTitle',
  465.         'showAllText',
  466.         'itemData',
  467.         'clearIfVoid',
  468.         'useSessions',
  469.         'closeSession',
  470.         'sessionVar',
  471.         'pearErrorMode',
  472.         'extraVars',
  473.         'excludeVars',
  474.         'currentPage',
  475.     );
  476.  
  477.     // }}}
  478.     // {{{ build()
  479.     
  480.     /**
  481.      * Generate or refresh the links and paged data after a call to setOptions()
  482.      *
  483.      * @access public
  484.      */
  485.     function build()
  486.     {
  487.         $msg = '<b>PEAR::Pager Error:</b>'
  488.               .' function "build()" not implemented.';
  489.         return $this->raiseError($msg, ERROR_PAGER_NOT_IMPLEMENTED);
  490.     }
  491.  
  492.     // }}}
  493.     // {{{ getPageData()
  494.  
  495.     /**
  496.      * Returns an array of current pages data
  497.      *
  498.      * @param $pageID Desired page ID (optional)
  499.      * @return array Page data
  500.      * @access public
  501.      */
  502.     function getPageData($pageID = null)
  503.     {
  504.         $pageID = empty($pageID) ? $this->_currentPage : $pageID;
  505.  
  506.         if (!isset($this->_pageData)) {
  507.             $this->_generatePageData();
  508.         }
  509.         if (!empty($this->_pageData[$pageID])) {
  510.             return $this->_pageData[$pageID];
  511.         }
  512.         return array();
  513.     }
  514.  
  515.     // }}}
  516.     // {{{ getPageIdByOffset()
  517.  
  518.     /**
  519.      * Returns pageID for given offset
  520.      *
  521.      * @param $index Offset to get pageID for
  522.      * @return int PageID for given offset
  523.      */
  524.     function getPageIdByOffset($index)
  525.     {
  526.         $msg = '<b>PEAR::Pager Error:</b>'
  527.               .' function "getPageIdByOffset()" not implemented.';
  528.         return $this->raiseError($msg, ERROR_PAGER_NOT_IMPLEMENTED);
  529.     }
  530.  
  531.     // }}}
  532.     // {{{ getOffsetByPageId()
  533.  
  534.     /**
  535.      * Returns offsets for given pageID. Eg, if you
  536.      * pass it pageID one and your perPage limit is 10
  537.      * it will return (1, 10). PageID of 2 would
  538.      * give you (11, 20).
  539.      *
  540.      * @param integer PageID to get offsets for
  541.      * @return array  First and last offsets
  542.      * @access public
  543.      */
  544.     function getOffsetByPageId($pageid = null)
  545.     {
  546.         $pageid = isset($pageid) ? $pageid : $this->_currentPage;
  547.         if (!isset($this->_pageData)) {
  548.             $this->_generatePageData();
  549.         }
  550.  
  551.         if (isset($this->_pageData[$pageid]) || is_null($this->_itemData)) {
  552.             return array(
  553.                         max(($this->_perPage * ($pageid - 1)) + 1, 1),
  554.                         min($this->_totalItems, $this->_perPage * $pageid)
  555.                    );
  556.         } else {
  557.             return array(0, 0);
  558.         }
  559.     }
  560.  
  561.     // }}}
  562.     // {{{ getPageRangeByPageId()
  563.  
  564.     /**
  565.      * @param integer PageID to get offsets for
  566.      * @return array  First and last offsets
  567.      */
  568.     function getPageRangeByPageId($pageID)
  569.     {
  570.         $msg = '<b>PEAR::Pager Error:</b>'
  571.               .' function "getPageRangeByPageId()" not implemented.';
  572.         return $this->raiseError($msg, ERROR_PAGER_NOT_IMPLEMENTED);
  573.     }
  574.  
  575.     // }}}
  576.     // {{{ getLinks()
  577.  
  578.     /**
  579.      * Returns back/next/first/last and page links,
  580.      * both as ordered and associative array.
  581.      *
  582.      * NB: in original PEAR::Pager this method accepted two parameters,
  583.      * $back_html and $next_html. Now the only parameter accepted is
  584.      * an integer ($pageID), since the html text for prev/next links can
  585.      * be set in the factory. If a second parameter is provided, then
  586.      * the method act as it previously did. This hack was done to mantain
  587.      * backward compatibility only.
  588.      *
  589.      * @param integer $pageID Optional pageID. If specified, links
  590.      *                for that page are provided instead of current one.  [ADDED IN NEW PAGER VERSION]
  591.      * @param  string $next_html HTML to put inside the next link [deprecated: use the factory instead]
  592.      * @return array back/next/first/last and page links
  593.      */
  594.     function getLinks($pageID=null, $next_html='')
  595.     {
  596.         $msg = '<b>PEAR::Pager Error:</b>'
  597.               .' function "getLinks()" not implemented.';
  598.         return $this->raiseError($msg, ERROR_PAGER_NOT_IMPLEMENTED);
  599.     }
  600.  
  601.     // }}}
  602.     // {{{ getCurrentPageID()
  603.  
  604.     /**
  605.      * Returns ID of current page
  606.      *
  607.      * @return integer ID of current page
  608.      */
  609.     function getCurrentPageID()
  610.     {
  611.         return $this->_currentPage;
  612.     }
  613.  
  614.     // }}}
  615.     // {{{ getNextPageID()
  616.  
  617.     /**
  618.      * Returns next page ID. If current page is last page
  619.      * this function returns FALSE
  620.      *
  621.      * @return mixed Next page ID
  622.      */
  623.     function getNextPageID()
  624.     {
  625.         return ($this->getCurrentPageID() == $this->numPages() ? false : $this->getCurrentPageID() + 1);
  626.     }
  627.  
  628.     // }}}
  629.     // {{{ getPreviousPageID()
  630.  
  631.     /**
  632.      * Returns previous page ID. If current page is first page
  633.      * this function returns FALSE
  634.      *
  635.      * @return mixed Previous pages' ID
  636.      */
  637.     function getPreviousPageID()
  638.     {
  639.         return $this->isFirstPage() ? false : $this->getCurrentPageID() - 1;
  640.     }
  641.  
  642.     // }}}
  643.     // {{{ numItems()
  644.  
  645.     /**
  646.      * Returns number of items
  647.      *
  648.      * @return int Number of items
  649.      */
  650.     function numItems()
  651.     {
  652.         return $this->_totalItems;
  653.     }
  654.  
  655.     // }}}
  656.     // {{{ numPages()
  657.  
  658.     /**
  659.      * Returns number of pages
  660.      *
  661.      * @return int Number of pages
  662.      */
  663.     function numPages()
  664.     {
  665.         return (int)$this->_totalPages;
  666.     }
  667.  
  668.     // }}}
  669.     // {{{ isFirstPage()
  670.  
  671.     /**
  672.      * Returns whether current page is first page
  673.      *
  674.      * @return bool First page or not
  675.      */
  676.     function isFirstPage()
  677.     {
  678.         return ($this->_currentPage < 2);
  679.     }
  680.  
  681.     // }}}
  682.     // {{{ isLastPage()
  683.  
  684.     /**
  685.      * Returns whether current page is last page
  686.      *
  687.      * @return bool Last page or not
  688.      */
  689.     function isLastPage()
  690.     {
  691.         return ($this->_currentPage == $this->_totalPages);
  692.     }
  693.  
  694.     // }}}
  695.     // {{{ isLastPageComplete()
  696.  
  697.     /**
  698.      * Returns whether last page is complete
  699.      *
  700.      * @return bool Last age complete or not
  701.      */
  702.     function isLastPageComplete()
  703.     {
  704.         return !($this->_totalItems % $this->_perPage);
  705.     }
  706.  
  707.     // }}}
  708.     // {{{ _generatePageData()
  709.  
  710.     /**
  711.      * Calculates all page data
  712.      * @access private
  713.      */
  714.     function _generatePageData()
  715.     {
  716.         // Been supplied an array of data?
  717.         if (!is_null($this->_itemData)) {
  718.             $this->_totalItems = count($this->_itemData);
  719.         }
  720.         $this->_totalPages = ceil((float)$this->_totalItems / (float)$this->_perPage);
  721.         $i = 1;
  722.         if (!empty($this->_itemData)) {
  723.             foreach ($this->_itemData as $key => $value) {
  724.                 $this->_pageData[$i][$key] = $value;
  725.                 if (count($this->_pageData[$i]) >= $this->_perPage) {
  726.                     $i++;
  727.                 }
  728.             }
  729.         } else {
  730.             $this->_pageData = array();
  731.         }
  732.  
  733.         //prevent URL modification
  734.         $this->_currentPage = min($this->_currentPage, $this->_totalPages);
  735.     }
  736.  
  737.     // }}}
  738.     // {{{ _renderLink()
  739.  
  740.     /**
  741.      * Renders a link using the appropriate method
  742.      *
  743.      * @param altText Alternative text for this link (title property)
  744.      * @param linkText Text contained by this link
  745.      * @return string The link in string form
  746.      * @access private
  747.      */
  748.     function _renderLink($altText, $linkText)
  749.     {
  750.         if ($this->_httpMethod == 'GET') {
  751.             if ($this->_append) {
  752.                 $href = '?' . $this->_http_build_query_wrapper($this->_linkData);
  753.             } else {
  754.                 $href = str_replace('%d', $this->_linkData[$this->_urlVar], $this->_fileName);
  755.             }
  756.             return sprintf('<a href="%s"%s%s%s title="%s">%s</a>',
  757.                            htmlentities($this->_url . $href),
  758.                            empty($this->_classString) ? '' : ' '.$this->_classString,
  759.                            empty($this->_attributes)  ? '' : ' '.$this->_attributes,
  760.                            empty($this->_accesskey)   ? '' : ' accesskey="'.$this->_linkData[$this->_urlVar].'"',
  761.                            $altText,
  762.                            $linkText
  763.             );
  764.         } elseif ($this->_httpMethod == 'POST') {
  765.             return sprintf("<a href='javascript:void(0)' onclick='%s'%s%s%s title='%s'>%s</a>",
  766.                            $this->_generateFormOnClick($this->_url, $this->_linkData),
  767.                            empty($this->_classString) ? '' : ' '.$this->_classString,
  768.                            empty($this->_attributes)  ? '' : ' '.$this->_attributes,
  769.                            empty($this->_accesskey)   ? '' : ' accesskey=\''.$this->_linkData[$this->_urlVar].'\'',
  770.                            $altText,
  771.                            $linkText
  772.             );
  773.         }
  774.         return '';
  775.     }
  776.  
  777.     // }}}
  778.     // {{{ _generateFormOnClick()
  779.  
  780.     /**
  781.      * Mimics http_build_query() behavior in the way the data
  782.      * in $data will appear when it makes it back to the server.
  783.      *  For example:
  784.      * $arr =  array('array' => array(array('hello', 'world'),
  785.      *                                'things' => array('stuff', 'junk'));
  786.      * http_build_query($arr)
  787.      * and _generateFormOnClick('foo.php', $arr)
  788.      * will yield
  789.      * $_REQUEST['array'][0][0] === 'hello'
  790.      * $_REQUEST['array'][0][1] === 'world'
  791.      * $_REQUEST['array']['things'][0] === 'stuff'
  792.      * $_REQUEST['array']['things'][1] === 'junk'
  793.      *
  794.      * However, instead of  generating a query string, it generates
  795.      * Javascript to create and submit a form.
  796.      *
  797.      * @param string $formAction where the form should be submitted
  798.      * @param array  $data the associative array of names and values
  799.      * @return string A string of javascript that generates a form and submits it
  800.      * @access private
  801.      */
  802.     function _generateFormOnClick($formAction, $data)
  803.     {
  804.         // Check we have an array to work with
  805.         if (!is_array($data)) {
  806.             trigger_error(
  807.                 '_generateForm() Parameter 1 expected to be Array or Object. Incorrect value given.',
  808.                 E_USER_WARNING
  809.             );
  810.             return false;
  811.         }
  812.  
  813.         if (!empty($this->_formID)) {
  814.             $str = 'var form = document.getElementById("'.$this->_formID.'"); var input = ""; ';
  815.         } else {
  816.             $str = 'var form = document.createElement("form"); var input = ""; ';
  817.         }
  818.         
  819.         // We /shouldn't/ need to escape the URL ...
  820.         $str .= sprintf('form.action = "%s"; ', htmlentities($formAction));
  821.         $str .= sprintf('form.method = "%s"; ', $this->_httpMethod);
  822.         foreach ($data as $key => $val) {
  823.             $str .= $this->_generateFormOnClickHelper($val, $key);
  824.         }
  825.  
  826.         if (empty($this->_formID)) {
  827.             $str .= 'document.getElementsByTagName("body")[0].appendChild(form);';
  828.         }
  829.         
  830.         $str .= 'form.submit(); return false;';
  831.         return $str;
  832.     }
  833.  
  834.     // }}}
  835.     // {{{ _generateFormOnClickHelper
  836.  
  837.     /**
  838.      * This is used by _generateFormOnClick(). 
  839.      * Recursively processes the arrays, objects, and literal values.
  840.      *
  841.      * @param data Data that should be rendered
  842.      * @param prev The name so far
  843.      * @return string A string of Javascript that creates form inputs
  844.      *                representing the data
  845.      * @access private
  846.      */
  847.     function _generateFormOnClickHelper($data, $prev = '')
  848.     {
  849.         $str = '';
  850.         if (is_array($data) || is_object($data)) {
  851.             // foreach key/visible member
  852.             foreach ((array)$data as $key => $val) {
  853.                 // append [$key] to prev
  854.                 $tempKey = sprintf('%s[%s]', $prev, $key);
  855.                 $str .= $this->_generateFormOnClickHelper($val, $tempKey);
  856.             }
  857.         } else {  // must be a literal value
  858.             // escape newlines and carriage returns
  859.             $search  = array("\n", "\r");
  860.             $replace = array('\n', '\n');
  861.             $escapedData = str_replace($search, $replace, $data);
  862.             // am I forgetting any dangerous whitespace?
  863.             // would a regex be faster?
  864.             // if it's already encoded, don't encode it again
  865.             if (!$this->_isEncoded($escapedData)) {
  866.                 $escapedData = urlencode($escapedData);
  867.             }
  868.             $escapedData = htmlentities($escapedData, ENT_QUOTES, 'UTF-8');
  869.  
  870.             $str .= 'input = document.createElement("input"); ';
  871.             $str .= 'input.type = "hidden"; ';
  872.             $str .= sprintf('input.name = "%s"; ', $prev);
  873.             $str .= sprintf('input.value = "%s"; ', $escapedData);
  874.             $str .= 'form.appendChild(input); ';
  875.         }
  876.         return $str;
  877.     }
  878.  
  879.     // }}}
  880.     // {{{ _getLinksData()
  881.  
  882.     /**
  883.      * Returns the correct link for the back/pages/next links
  884.      *
  885.      * @return array Data
  886.      * @access private
  887.      */
  888.     function _getLinksData()
  889.     {
  890.         $qs = array();
  891.         if ($this->_importQuery) {
  892.             if ($this->_httpMethod == 'POST') {
  893.                 $qs = $_POST;
  894.             } elseif ($this->_httpMethod == 'GET') {
  895.                 $qs = $_GET;
  896.             }
  897.         }
  898.         foreach ($this->_excludeVars as $exclude) {
  899.             if (array_key_exists($exclude, $qs)) {
  900.                 unset($qs[$exclude]);
  901.             }
  902.         }
  903.         if (count($this->_extraVars)){
  904.             $this->_recursive_urldecode($this->_extraVars);
  905.             $qs = array_merge($qs, $this->_extraVars);
  906.         }
  907.         if (count($qs) && get_magic_quotes_gpc()){
  908.             $this->_recursive_stripslashes($qs);
  909.         }
  910.         return $qs;
  911.     }
  912.  
  913.     // }}}
  914.     // {{{ _recursive_stripslashes()
  915.     
  916.     /**
  917.      * Helper method
  918.      * @param mixed $var
  919.      * @access private
  920.      */
  921.     function _recursive_stripslashes(&$var)
  922.     {
  923.         if (is_array($var)) {
  924.             foreach (array_keys($var) as $k) {
  925.                 $this->_recursive_stripslashes($var[$k]);
  926.             }
  927.         } else {
  928.             $var = stripslashes($var);
  929.         }
  930.     }
  931.  
  932.     // }}}
  933.     // {{{ _recursive_urldecode()
  934.  
  935.     /**
  936.      * Helper method
  937.      * @param mixed $var
  938.      * @access private
  939.      */
  940.     function _recursive_urldecode(&$var)
  941.     {
  942.         if (is_array($var)) {
  943.             foreach (array_keys($var) as $k) {
  944.                 $this->_recursive_urldecode($var[$k]);
  945.             }
  946.         } else {
  947.             $trans_tbl = array_flip(get_html_translation_table(HTML_ENTITIES));
  948.             $var = strtr($var, $trans_tbl);
  949.         }
  950.     }
  951.  
  952.     // }}}
  953.     // {{{ _getBackLink()
  954.  
  955.     /**
  956.      * Returns back link
  957.      *
  958.      * @param $url  URL to use in the link  [deprecated: use the factory instead]
  959.      * @param $link HTML to use as the link [deprecated: use the factory instead]
  960.      * @return string The link
  961.      * @access private
  962.      */
  963.     function _getBackLink($url='', $link='')
  964.     {
  965.         //legacy settings... the preferred way to set an option
  966.         //now is passing it to the factory
  967.         if (!empty($url)) {
  968.             $this->_path = $url;
  969.         }
  970.         if (!empty($link)) {
  971.             $this->_prevImg = $link;
  972.         }
  973.         $back = '';
  974.         if ($this->_currentPage > 1) {
  975.             $this->_linkData[$this->_urlVar] = $this->getPreviousPageID();
  976.             $back = $this->_renderLink($this->_altPrev, $this->_prevImg)
  977.                   . $this->_spacesBefore . $this->_spacesAfter;
  978.         }
  979.         return $back;
  980.     }
  981.  
  982.     // }}}
  983.     // {{{ _getPageLinks()
  984.  
  985.     /**
  986.      * Returns pages link
  987.      *
  988.      * @param $url  URL to use in the link [deprecated: use the factory instead]
  989.      * @return string Links
  990.      * @access private
  991.      */
  992.     function _getPageLinks($url='')
  993.     {
  994.         $msg = '<b>PEAR::Pager Error:</b>'
  995.               .' function "_getPageLinks()" not implemented.';
  996.         return $this->raiseError($msg, ERROR_PAGER_NOT_IMPLEMENTED);
  997.     }
  998.  
  999.     // }}}
  1000.     // {{{ _getNextLink()
  1001.  
  1002.     /**
  1003.      * Returns next link
  1004.      *
  1005.      * @param $url  URL to use in the link  [deprecated: use the factory instead]
  1006.      * @param $link HTML to use as the link [deprecated: use the factory instead]
  1007.      * @return string The link
  1008.      * @access private
  1009.      */
  1010.     function _getNextLink($url='', $link='')
  1011.     {
  1012.         //legacy settings... the preferred way to set an option
  1013.         //now is passing it to the factory
  1014.         if (!empty($url)) {
  1015.             $this->_path = $url;
  1016.         }
  1017.         if (!empty($link)) {
  1018.             $this->_nextImg = $link;
  1019.         }
  1020.         $next = '';
  1021.         if ($this->_currentPage < $this->_totalPages) {
  1022.             $this->_linkData[$this->_urlVar] = $this->getNextPageID();
  1023.             $next = $this->_spacesAfter
  1024.                   . $this->_renderLink($this->_altNext, $this->_nextImg)
  1025.                   . $this->_spacesBefore . $this->_spacesAfter;
  1026.         }
  1027.         return $next;
  1028.     }
  1029.  
  1030.     // }}}
  1031.     // {{{ _getFirstLinkTag()
  1032.  
  1033.     /**
  1034.      * @return string
  1035.      * @access private
  1036.      */
  1037.     function _getFirstLinkTag()
  1038.     {
  1039.         if ($this->isFirstPage() || ($this->_httpMethod != 'GET')) {
  1040.             return '';
  1041.         }
  1042.         return sprintf('<link rel="first" href="%s" title="%s" />'."\n",
  1043.             $this->_getLinkTagUrl(1),
  1044.             $this->_firstLinkTitle
  1045.         );
  1046.     }
  1047.  
  1048.     // }}}
  1049.     // {{{ _getPrevLinkTag()
  1050.  
  1051.     /**
  1052.      * Returns previous link tag
  1053.      *
  1054.      * @return string the link tag
  1055.      * @access private
  1056.      */
  1057.     function _getPrevLinkTag()
  1058.     {
  1059.         if ($this->isFirstPage() || ($this->_httpMethod != 'GET')) {
  1060.             return '';
  1061.         }
  1062.         return sprintf('<link rel="previous" href="%s" title="%s" />'."\n",
  1063.             $this->_getLinkTagUrl($this->getPreviousPageID()),
  1064.             $this->_prevLinkTitle
  1065.         );
  1066.     }
  1067.  
  1068.     // }}}
  1069.     // {{{ _getNextLinkTag()
  1070.  
  1071.     /**
  1072.      * Returns next link tag
  1073.      *
  1074.      * @return string the link tag
  1075.      * @access private
  1076.      */
  1077.     function _getNextLinkTag()
  1078.     {
  1079.         if ($this->isLastPage() || ($this->_httpMethod != 'GET')) {
  1080.             return '';
  1081.         }
  1082.         return sprintf('<link rel="next" href="%s" title="%s" />'."\n",
  1083.             $this->_getLinkTagUrl($this->getNextPageID()),
  1084.             $this->_nextLinkTitle
  1085.         );
  1086.     }
  1087.  
  1088.     // }}}
  1089.     // {{{ _getLastLinkTag()
  1090.  
  1091.     /**
  1092.      * @return string the link tag
  1093.      * @access private
  1094.      */
  1095.     function _getLastLinkTag()
  1096.     {
  1097.         if ($this->isLastPage() || ($this->_httpMethod != 'GET')) {
  1098.             return '';
  1099.         }
  1100.         return sprintf('<link rel="last" href="%s" title="%s" />'."\n",
  1101.             $this->_getLinkTagUrl($this->_totalPages),
  1102.             $this->_lastLinkTitle
  1103.         );
  1104.     }
  1105.  
  1106.     // }}}
  1107.     // {{{ _getLinkTagUrl()
  1108.  
  1109.     /**
  1110.      * Helper method
  1111.      * @return string the link tag url
  1112.      * @access private
  1113.      */
  1114.     function _getLinkTagUrl($pageID)
  1115.     {
  1116.         $this->_linkData[$this->_urlVar] = $pageID;
  1117.         if ($this->_append) {
  1118.             $href = '?' . $this->_http_build_query_wrapper($this->_linkData);
  1119.         } else {
  1120.             $href = str_replace('%d', $this->_linkData[$this->_urlVar], $this->_fileName);
  1121.         }
  1122.         return htmlentities($this->_url . $href);
  1123.     }
  1124.     
  1125.     // }}}
  1126.     // {{{ getPerPageSelectBox()
  1127.  
  1128.     /**
  1129.      * Returns a string with a XHTML SELECT menu,
  1130.      * useful for letting the user choose how many items per page should be
  1131.      * displayed. If parameter useSessions is TRUE, this value is stored in
  1132.      * a session var. The string isn't echoed right now so you can use it
  1133.      * with template engines.
  1134.      *
  1135.      * @param integer $start
  1136.      * @param integer $end
  1137.      * @param integer $step
  1138.      * @param boolean $showAllData If true, perPage is set equal to totalItems.
  1139.      * @param array   (or string $optionText for BC reasons)
  1140.      *                - 'optionText': text to show in each option.
  1141.      *                  Use '%d' where you want to see the number of pages selected.
  1142.      *                - 'attributes': (html attributes) Tag attributes or
  1143.      *                  HTML attributes (id="foo" pairs), will be inserted in the
  1144.      *                  <select> tag
  1145.      * @return string xhtml select box
  1146.      * @access public
  1147.      */
  1148.     function getPerPageSelectBox($start=5, $end=30, $step=5, $showAllData=false, $extraParams=array())
  1149.     {
  1150.         require_once 'Pager/HtmlWidgets.php';
  1151.         $widget =& new Pager_HtmlWidgets($this);
  1152.         return $widget->getPerPageSelectBox($start, $end, $step, $showAllData, $extraParams);
  1153.     }
  1154.  
  1155.     // }}}
  1156.     // {{{ getPageSelectBox()
  1157.  
  1158.     /**
  1159.      * Returns a string with a XHTML SELECT menu with the page numbers,
  1160.      * useful as an alternative to the links
  1161.      *
  1162.      * @param array   - 'optionText': text to show in each option.
  1163.      *                  Use '%d' where you want to see the number of pages selected.
  1164.      *                - 'autoSubmit': if TRUE, add some js code to submit the
  1165.      *                  form on the onChange event
  1166.      * @param string   $extraAttributes (html attributes) Tag attributes or
  1167.      *                  HTML attributes (id="foo" pairs), will be inserted in the
  1168.      *                  <select> tag
  1169.      * @return string xhtml select box
  1170.      * @access public
  1171.      */
  1172.     function getPageSelectBox($params = array(), $extraAttributes = '')
  1173.     {
  1174.         require_once 'Pager/HtmlWidgets.php';
  1175.         $widget =& new Pager_HtmlWidgets($this);
  1176.         return $widget->getPageSelectBox($params, $extraAttributes);
  1177.     }
  1178.  
  1179.     // }}}
  1180.     // {{{ _printFirstPage()
  1181.  
  1182.     /**
  1183.      * Print [1]
  1184.      *
  1185.      * @return string String with link to 1st page,
  1186.      *                or empty string if this is the 1st page.
  1187.      * @access private
  1188.      */
  1189.     function _printFirstPage()
  1190.     {
  1191.         if ($this->isFirstPage()) {
  1192.             return '';
  1193.         }
  1194.         $this->_linkData[$this->_urlVar] = 1;
  1195.         return $this->_renderLink(
  1196.                 str_replace('%d', 1, $this->_altFirst),
  1197.                 $this->_firstPagePre . $this->_firstPageText . $this->_firstPagePost
  1198.         ) . $this->_spacesBefore . $this->_spacesAfter;
  1199.     }
  1200.  
  1201.     // }}}
  1202.     // {{{ _printLastPage()
  1203.  
  1204.     /**
  1205.      * Print [numPages()]
  1206.      *
  1207.      * @return string String with link to last page,
  1208.      *                or empty string if this is the 1st page.
  1209.      * @access private
  1210.      */
  1211.     function _printLastPage()
  1212.     {
  1213.         if ($this->isLastPage()) {
  1214.             return '';
  1215.         }
  1216.         $this->_linkData[$this->_urlVar] = $this->_totalPages;
  1217.         return $this->_renderLink(
  1218.                 str_replace('%d', $this->_totalPages, $this->_altLast),
  1219.                 $this->_lastPagePre . $this->_lastPageText . $this->_lastPagePost
  1220.         );
  1221.     }
  1222.  
  1223.     // }}}
  1224.     // {{{ _setFirstLastText()
  1225.  
  1226.     /**
  1227.      * sets the private _firstPageText, _lastPageText variables
  1228.      * based on whether they were set in the options
  1229.      *
  1230.      * @access private
  1231.      */
  1232.     function _setFirstLastText()
  1233.     {
  1234.         if ($this->_firstPageText == '') {
  1235.             $this->_firstPageText = '1';
  1236.         }
  1237.         if ($this->_lastPageText == '') {
  1238.             $this->_lastPageText = $this->_totalPages;
  1239.         }
  1240.     }
  1241.  
  1242.     // }}}
  1243.     // {{{ _http_build_query_wrapper()
  1244.     
  1245.     /**
  1246.      * This is a slightly modified version of the http_build_query() function;
  1247.      * it heavily borrows code from PHP_Compat's http_build_query().
  1248.      * The main change is the usage of htmlentities instead of urlencode,
  1249.      * since it's too aggressive
  1250.      *
  1251.      * @author Stephan Schmidt <schst@php.net>
  1252.      * @author Aidan Lister <aidan@php.net>
  1253.      * @author Lorenzo Alberton <l dot alberton at quipo dot it>
  1254.      * @param array $data
  1255.      * @return string
  1256.      * @access private
  1257.      */
  1258.     function _http_build_query_wrapper($data)
  1259.     {
  1260.         $data = (array)$data;
  1261.         if (empty($data)) {
  1262.             return '';
  1263.         }
  1264.         $separator = ini_get('arg_separator.output');
  1265.         if ($separator == '&') {
  1266.             $separator = '&'; //the string is escaped by htmlentities anyway...
  1267.         }
  1268.         $tmp = array ();
  1269.         foreach ($data as $key => $val) {
  1270.             if (is_scalar($val)) {
  1271.                 //array_push($tmp, $key.'='.$val);
  1272.                 $val = urlencode($val);
  1273.                 array_push($tmp, $key .'='. str_replace('%2F', '/', $val));
  1274.                 continue;
  1275.             }
  1276.             // If the value is an array, recursively parse it
  1277.             if (is_array($val)) {
  1278.                 array_push($tmp, $this->__http_build_query($val, htmlentities($key)));
  1279.                 continue;
  1280.             }
  1281.         }
  1282.         return implode($separator, $tmp);
  1283.     }
  1284.  
  1285.     // }}}
  1286.     // {{{ __http_build_query()
  1287.  
  1288.     /**
  1289.      * Helper function
  1290.      * @author Stephan Schmidt <schst@php.net>
  1291.      * @author Aidan Lister <aidan@php.net>
  1292.      * @access private
  1293.      */
  1294.     function __http_build_query($array, $name)
  1295.     {
  1296.         $tmp = array ();
  1297.         $separator = ini_get('arg_separator.output');
  1298.         if ($separator == '&') {
  1299.             $separator = '&'; //the string is escaped by htmlentities anyway...
  1300.         }
  1301.         foreach ($array as $key => $value) {
  1302.             if (is_array($value)) {
  1303.                 //array_push($tmp, $this->__http_build_query($value, sprintf('%s[%s]', $name, $key)));
  1304.                 array_push($tmp, $this->__http_build_query($value, $name.'%5B'.$key.'%5D'));
  1305.             } elseif (is_scalar($value)) {
  1306.                 //array_push($tmp, sprintf('%s[%s]=%s', $name, htmlentities($key), htmlentities($value)));
  1307.                 array_push($tmp, $name.'%5B'.htmlentities($key).'%5D='.htmlentities($value));
  1308.             } elseif (is_object($value)) {
  1309.                 //array_push($tmp, $this->__http_build_query(get_object_vars($value), sprintf('%s[%s]', $name, $key)));
  1310.                 array_push($tmp, $this->__http_build_query(get_object_vars($value), $name.'%5B'.$key.'%5D'));
  1311.             }
  1312.         }
  1313.         return implode($separator, $tmp);
  1314.     }
  1315.  
  1316.     // }}}
  1317.     // {{{ _isEncoded()
  1318.  
  1319.     /**
  1320.      * Helper function
  1321.      * Check if a string is an encoded multibyte string
  1322.      * @param string $string
  1323.      * @return boolean
  1324.      * @access private
  1325.      */
  1326.     
  1327.     function _isEncoded($string)
  1328.     {
  1329.         $hexchar = '&#[\dA-Fx]{2,};';
  1330.         return preg_match("/^(\s|($hexchar))*$/Uims", $string) ? true : false;
  1331.     }
  1332.  
  1333.     // }}}
  1334.     // {{{ raiseError()
  1335.  
  1336.     /**
  1337.      * conditionally includes PEAR base class and raise an error
  1338.      *
  1339.      * @param string $msg  Error message
  1340.      * @param int    $code Error code
  1341.      * @access private
  1342.      */
  1343.     function raiseError($msg, $code)
  1344.     {
  1345.         include_once 'PEAR.php';
  1346.         if (empty($this->_pearErrorMode)) {
  1347.             $this->_pearErrorMode = PEAR_ERROR_RETURN;
  1348.         }
  1349.         return PEAR::raiseError($msg, $code, $this->_pearErrorMode);
  1350.     }
  1351.  
  1352.     // }}}
  1353.     // {{{ setOptions()
  1354.  
  1355.     /**
  1356.      * Set and sanitize options
  1357.      *
  1358.      * @param mixed $options    An associative array of option names and
  1359.      *                          their values.
  1360.      * @return integer error code (PAGER_OK on success)
  1361.      * @access public
  1362.      */
  1363.     function setOptions($options)
  1364.     {
  1365.         foreach ($options as $key => $value) {
  1366.             if (in_array($key, $this->_allowed_options) && (!is_null($value))) {
  1367.                 $this->{'_' . $key} = $value;
  1368.             }
  1369.         }
  1370.  
  1371.         //autodetect http method
  1372.         if (!isset($options['httpMethod'])
  1373.             && !isset($_GET[$this->_urlVar])
  1374.             && isset($_POST[$this->_urlVar])
  1375.         ) {
  1376.             $this->_httpMethod = 'POST';
  1377.         } else {
  1378.             $this->_httpMethod = strtoupper($this->_httpMethod);
  1379.         }
  1380.  
  1381.         $this->_fileName = ltrim($this->_fileName, '/');  //strip leading slash
  1382.         $this->_path     = rtrim($this->_path, '/');      //strip trailing slash
  1383.  
  1384.         if ($this->_append) {
  1385.             if ($this->_fixFileName) {
  1386.                 $this->_fileName = CURRENT_FILENAME; //avoid possible user error;
  1387.             }
  1388.             $this->_url = $this->_path.'/'.$this->_fileName;
  1389.         } else {
  1390.             $this->_url = $this->_path;
  1391.             if (strncasecmp($this->_fileName, 'javascript', 10) != 0) {
  1392.                 $this->_url .= '/';
  1393.             }
  1394.             if (!strstr($this->_fileName, '%d')) {
  1395.                 trigger_error($this->errorMessage(ERROR_PAGER_INVALID_USAGE), E_USER_WARNING);
  1396.             }
  1397.         }
  1398.  
  1399.         $this->_classString = '';
  1400.         if (strlen($this->_linkClass)) {
  1401.             $this->_classString = 'class="'.$this->_linkClass.'"';
  1402.         }
  1403.  
  1404.         if (strlen($this->_curPageLinkClassName)) {
  1405.             $this->_curPageSpanPre  = '<span class="'.$this->_curPageLinkClassName.'">';
  1406.             $this->_curPageSpanPost = '</span>';
  1407.         }
  1408.  
  1409.         $this->_perPage = max($this->_perPage, 1); //avoid possible user errors
  1410.  
  1411.         if ($this->_useSessions && !isset($_SESSION)) {
  1412.             session_start();
  1413.         }
  1414.         if (!empty($_REQUEST[$this->_sessionVar])) {
  1415.             $this->_perPage = max(1, (int)$_REQUEST[$this->_sessionVar]);
  1416.             if ($this->_useSessions) {
  1417.                 $_SESSION[$this->_sessionVar] = $this->_perPage;
  1418.             }
  1419.         }
  1420.  
  1421.         if (!empty($_SESSION[$this->_sessionVar])) {
  1422.              $this->_perPage = $_SESSION[$this->_sessionVar];
  1423.         }
  1424.  
  1425.         if ($this->_closeSession) {
  1426.             session_write_close();
  1427.         }
  1428.  
  1429.         $this->_spacesBefore = str_repeat(' ', $this->_spacesBeforeSeparator);
  1430.         $this->_spacesAfter  = str_repeat(' ', $this->_spacesAfterSeparator);
  1431.  
  1432.         if (isset($_REQUEST[$this->_urlVar]) && empty($options['currentPage'])) {
  1433.             $this->_currentPage = (int)$_REQUEST[$this->_urlVar];
  1434.         }
  1435.         $this->_currentPage = max($this->_currentPage, 1);
  1436.         $this->_linkData = $this->_getLinksData();
  1437.  
  1438.         return PAGER_OK;
  1439.     }
  1440.  
  1441.     // }}}
  1442.     // {{{ getOption()
  1443.     
  1444.     /**
  1445.      * Return the current value of a given option
  1446.      *
  1447.      * @param string option name
  1448.      * @return mixed option value
  1449.      */
  1450.     function getOption($name)
  1451.     {
  1452.         if (!in_array($name, $this->_allowed_options)) {
  1453.             $msg = '<b>PEAR::Pager Error:</b>'
  1454.                   .' invalid option: '.$name;
  1455.             return $this->raiseError($msg, ERROR_PAGER_INVALID);
  1456.         }
  1457.         return $this->{'_' . $name};
  1458.     }
  1459.  
  1460.     // }}}
  1461.     // {{{ getOptions()
  1462.  
  1463.     /**
  1464.      * Return an array with all the current pager options
  1465.      *
  1466.      * @return array list of all the pager options
  1467.      */
  1468.     function getOptions()
  1469.     {
  1470.         $options = array();
  1471.         foreach ($this->_allowed_options as $option) {
  1472.             $options[$option] = $this->{'_' . $option};
  1473.         }
  1474.         return $options;
  1475.     }
  1476.  
  1477.     // }}}
  1478.     // {{{ errorMessage()
  1479.  
  1480.     /**
  1481.      * Return a textual error message for a PAGER error code
  1482.      *
  1483.      * @param   int     $code error code
  1484.      * @return  string  error message
  1485.      * @access public
  1486.      */
  1487.     function errorMessage($code)
  1488.     {
  1489.         static $errorMessages;
  1490.         if (!isset($errorMessages)) {
  1491.             $errorMessages = array(
  1492.                 ERROR_PAGER                     => 'unknown error',
  1493.                 ERROR_PAGER_INVALID             => 'invalid',
  1494.                 ERROR_PAGER_INVALID_PLACEHOLDER => 'invalid format - use "%d" as placeholder.',
  1495.                 ERROR_PAGER_INVALID_USAGE       => 'if $options[\'append\'] is set to false, '
  1496.                                                   .' $options[\'fileName\'] MUST contain the "%d" placeholder.',
  1497.                 ERROR_PAGER_NOT_IMPLEMENTED     => 'not implemented'
  1498.             );
  1499.         }
  1500.  
  1501.         return '<b>PEAR::Pager error:</b> '. (isset($errorMessages[$code]) ?
  1502.             $errorMessages[$code] : $errorMessages[ERROR_PAGER]);
  1503.     }
  1504.  
  1505.     // }}}
  1506. }
  1507. ?>